package com.bigknow.appstore.web.console.service.impl;

import com.bigknow.appstore.common.constants.DateFormatConstants;
import com.bigknow.appstore.proxy.cache.impl.EhCacheManager;
import com.bigknow.appstore.proxy.entity.ProxyMeta;
import com.bigknow.appstore.proxy.entity.ProxyResourceMeta;
import com.bigknow.appstore.proxy.service.ProxyManager;
import com.bigknow.appstore.proxy.cache.impl.EhCacheManager;
import com.bigknow.appstore.proxy.entity.ProxyMeta;
import com.bigknow.appstore.proxy.entity.ProxyResourceMeta;
import com.bigknow.appstore.proxy.service.ProxyManager;
import com.bigknow.appstore.web.base.entity.User;
import com.bigknow.appstore.web.console.app.Application;
import com.bigknow.appstore.web.console.app.ApplicationSSOConfig;
import com.bigknow.appstore.web.console.app.ApplicationState;
import com.bigknow.appstore.web.console.app.Tag;
import com.bigknow.appstore.web.console.dao.IApplicationDao;
import com.bigknow.appstore.web.console.service.IApplicationService;
import com.bigknow.appstore.web.framework.service.BaseCRUDService;
import com.bigknow.appstore.web.util.PinyinUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.bson.types.ObjectId;
import org.mongodb.morphia.Datastore;
import org.mongodb.morphia.query.Query;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * Created by 李科风 on 2016-09-22.
 */
@Service
public class ApplicationService extends BaseCRUDService<Application, IApplicationDao> implements IApplicationService {

    @Value("${app.server.ip}")
    private String ip;

    @Autowired
    private Datastore ds;

    @Autowired
    private ApplicationCategoryService applicationCategoryService;

    @Autowired
    private EhCacheManager ehCacheManager;

    @Override
    public Application get(String id) {
        Application app = super.get(id);
        if (app != null) {
            app.setCategory(applicationCategoryService.getCategory(app.getCategoryId()));
            app.setTags(loadTags(app.getTags()));
        }
        return app;
    }

    @Override
    public int insert(Application application) {
        Subject subject = SecurityUtils.getSubject();
        User user = (User) subject.getPrincipal();
        Date date = new Date();
        String now = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);

        application.setState(ApplicationState.TEST);
        application.setUserId(user.getId());
        application.setCreateTime(now);
        application.setUpdateTime(now);
        application.setSubscribeCount(0);
        application.setStar(0f);

        ApplicationSSOConfig ssoConfig = new ApplicationSSOConfig();
        ssoConfig.setGrantType("authorization_code");
        ssoConfig.setClientId(generateClientId(application.getName(), application.getContext()));
        ssoConfig.setClientSecret(generateClientSecret(application.getName(), application.getContext(), date.getTime()));
        ssoConfig.setRedirectURL("zwtcAppStoretoken");
        application.setSsoConfig(ssoConfig);

        application.setTags(filterTagIds(application.getTags()));

        int returnValue = super.insert(application);
        //更新缓存
        ehCacheManager.getProxyResCache(application.getProxyMetaId())
                .addOrUpdateCache(ProxyResourceMeta.toProxyResMeta(application));
        return returnValue;
    }

    private List<String> filterTagIds(List<String> tags) {
        List<String> tagIds = new ArrayList<String>();
        for (String idOrName : tags) {
            Tag tag = ds.find(Tag.class).filter("id", idOrName.trim()).get();
            if (tag == null) {
                Tag _tag = ds.find(Tag.class).filter("name", idOrName.trim()).get();
                if (_tag == null) {
                    Tag newTag = new Tag();
                    newTag.setName(idOrName.trim());
                    newTag.setId(UUID.randomUUID().toString());
                    String newTagId = ds.save(newTag).getId().toString();
                    if (!tags.contains(newTagId)) {
                        tagIds.add(newTagId);
                    }
                } else {
                    if (!tags.contains(_tag.getId())) {
                        tagIds.add(_tag.getId());
                    }
                }
            } else {
                tagIds.add(tag.getId());
            }
        }
        return tagIds;
    }

    private String generateClientId(String name, String context) {
        return PinyinUtils.getFirstUpperCase(name) + "_" + StringUtils.upperCase(context);
    }

    private String generateClientSecret(String name, String context, long now) {
        return PinyinUtils.getFirstUpperCase(name) + "_" + StringUtils.upperCase(context) + "_" + now;
    }

    @Override
    public int update(Application app) {
        Application old = get(app.getId());
        app.setUserId(old.getUserId());
        app.setCreateTime(app.getCreateTime());
        app.setUpdateTime(DateFormatConstants.getCurrentTime(DateFormatConstants.F_1));
        app.setSubscribeCount(old.getSubscribeCount());
        app.setStar(old.getStar());
        app.setPreVersionId(old.getPreVersionId());
        app.setCreateTime(old.getCreateTime());
        app.setTags(filterTagIds(app.getTags()));
        if (StringUtils.equals(app.getName(), old.getName()) && StringUtils.equals(app.getContext(), old.getContext())) {
            app.setSsoConfig(old.getSsoConfig());
        } else {
            ApplicationSSOConfig ssoConfig = new ApplicationSSOConfig();
            ssoConfig.setGrantType("authorization_code");
            ssoConfig.setClientId(generateClientId(app.getName(), app.getContext()));
            ssoConfig.setClientSecret(generateClientSecret(app.getName(), app.getContext(), new Date().getTime()));
            ssoConfig.setRedirectURL("zwtcAppStoretoken");
            app.setSsoConfig(ssoConfig);
        }
        if (app.getState() == null) {
            app.setState(old.getState());
        }
        if (app.getLogoFile() != null && app.getLogoFile().isEmpty()) {
            app.setLogoFile(old.getLogoFile());
        }
        if (app.getScreenshotFiles() != null && app.getScreenshotFiles().isEmpty()) {
            app.setScreenshotFiles(old.getScreenshotFiles());
        }
        if (app.getHelpFiles() != null && app.getHelpFiles().isEmpty()) {
            app.setHelpFiles(old.getHelpFiles());
        }

        //更新缓存
        ehCacheManager.getProxyResCache(app.getProxyMetaId())
                .addOrUpdateCache(ProxyResourceMeta.toProxyResMeta(app));
        return super.update(app);
    }

    @Override
    public String getUrl(String id) {
        Application app = ds.find(Application.class).field("id").equal(id).get();
        if (app != null) {
//            StringBuilder builder = new StringBuilder();
//            ProxyMeta pm = ds.find(ProxyMeta.class).field("id").equal(app.getProxyMetaId()).get();
//            if (pm.isHTTPS()) {
//                builder.append("https://");
//            } else {
//                builder.append("http://");
//            }
//            builder.append(ip).append(":").append(pm.getPort()).append("/").append(app.getContext())
//                    .append("/").append(app.getVersion());

//            return builder.toString();
            return app.getIndexUrl();
        } else {
            return "";
        }
    }

    public int retire(String appId) {
        if (!StringUtils.isEmpty(appId)) {
            Application app = ds.find(Application.class, "id", appId).get();
            if (app != null) {
                ds.update(app, ds.createUpdateOperations(Application.class).set("state", ApplicationState.DEPRECATED).set("updateTime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
                app.setState(ApplicationState.DEPRECATED);
                ehCacheManager.getProxyResCache(app.getProxyMetaId()).deleteCache(ProxyResourceMeta.toProxyResMeta(app));
                return 1;
            }
        }
        return 0;
    }

    private List<String> loadTags(List<String> ids) {
        List<String> names = new ArrayList<String>();
        for (String id : ids) {
            names.add(ds.find(Tag.class).filter("id", id).get().getName());
        }
        return names;
    }

    public int publish(String appId) {
        if (!StringUtils.isEmpty(appId)) {
            Application app = ds.find(Application.class, "id", appId).get();
            if (app != null) {
                Date now = new Date();
                ds.update(app, ds.createUpdateOperations(Application.class).set("state", ApplicationState.APPLYING).set("updateTime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(now)).set("publishedTime", now.getTime()));
                app.setState(ApplicationState.APPLYING);
                ehCacheManager.getProxyResCache(app.getProxyMetaId())
                        .addOrUpdateCache(ProxyResourceMeta.toProxyResMeta(app));
                return 1;
            }
        }
        return 0;
    }

    public int cancelPublish(String appId) {
        if (!StringUtils.isEmpty(appId)) {
            Application app = ds.find(Application.class, "id", appId).get();
            if (app != null) {
                ds.update(app, ds.createUpdateOperations(Application.class).set("state", ApplicationState.TEST).set("updateTime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
                app.setState(ApplicationState.TEST);
                ehCacheManager.getProxyResCache(app.getProxyMetaId())
                        .addOrUpdateCache(ProxyResourceMeta.toProxyResMeta(app));
                return 1;
            }
        }
        return 0;
    }

    public String getAppName(String id) {
        if (!StringUtils.isEmpty(id)) {
            Application app = ds.find(Application.class).filter("id", id).get();
            if (app != null) {
                return app.getDisplayName();
            }
        }
        return null;
    }
}
